'''图片上传管理器类UploadManager,从原来的UploaderManager改装过来的.

抽象类Uploader是上传器类,规定上传的基本行为.
继承该类的子类必须重载_upload方法,即具体如何上传,返回什么.
主要方法是upload,上传并返回指定格式的结果,上传失败返回None

---
目前做好的几个子类:
imgurl_org_Uploader,匿名图床imgurl.org的上传,此图床效果不错;
png8_com_Uploader,匿名图床www.png8.com的上传,此图床效果不错,
  与imgurl.org是同一引擎方法完全一样;
sm_ms_Uploader,匿名图床sm.ms的上传,这图床的图片显示效果不好;
img_vim_cn_com_Uploader类,匿名图床img.vim-cn.com的上传,效果不错而且简单;
niupic_com_Uploader类,匿名图床牛图网niupic.com的上传,效果不错;

作者: setycyas
最后修改: 2020-02-22
'''

import os
import sys
import json
import urllib
import abc
import time

import requests

### 上传器类 ###

class Uploader(metaclass = abc.ABCMeta):
  '''抽象类Uploader,所有上传器类的基类.
  
  规定了上传时的方法参数,上传后的数据处理.域名domain是每个上传器的指定标识,
  继承时必须指定.同时继承时必须重写_uploadFile方法
  
  [公有方法]
  构造方法(self, domain), 指定域名.
  upload(self, filepath, tags, _type),上传一个文件.
  '''

  def __init__(self, domain):
    '''构造方法
    
    @domain: 指定上传的域名(str)
    '''
    self._domain = domain
    return
    
  ### 公有方法
  
  def upload(self, filepath, tags = [], _type = 'default'):
    '''用_uploadFile上传一个文件并进行数据的检验,记录等操作.
    
    @filepath: 要上传的文件路径(str).
    @tags: 该文件的指定标签组([str]).
    @_type: 指定分类(str).
    
    Returns:成功则根据_uploadFile的返回值,返回{'name', 'url', 'tags', 'data',
      'type'},失败返回None.
    '''
    ## 检查上传文件
    if (not (os.path.exists(filepath))):
      ('Upload failed!Can not find filepath:{}!'.format(filepath))
      return None
    ## 生成记录的文件名
    name = filepath.split('\\')[-1] 
    ## 上传文件,对返回结果进行判断,编辑
    print('Uploading {0} to {1}'.format(filepath, self._domain))
    result = None
    resp = self._uploadFile(filepath)
    if (resp):
      result = {'name': name, 'tags': tags, 'time': int(time.time()),
        'content': resp['url'], 'type': _type}
      print('Upload {} successed!'.format(filepath))
    else:
      print('Upload {} failed!Something wrong when uploading file!'.format(
        filepath))
    return result
    
  ### 私有方法
  
  @abc.abstractmethod
  def _uploadFile(self, filepath):
    '''文件上传方法.必须重载!
    
    @filepath: 上传的图片文件路径(str).
    
    Returns:成功返回{'url':图片的url, 'data':上传的返回信息字符串},
      失败返回None
    '''
    return
  
class imgurl_org_Uploader(Uploader):
  '''继承抽象类Uploader的imgurl_org_Uploader类,
  域名imgurl.org(89.208.250.90)
  '''

  def __init__(self):
    Uploader.__init__(self, 'imgurl.org')
    return
    
  def _uploadFile(self, filepath):
    apiUrl = r'https://imgurl.org/api/upload' # 上传文件url
    filename = urllib.parse.quote(os.path.basename(filepath)) # 处理文件名
    ## 制作上传需要的数据资料
    try:
      file = open(filepath,'rb')
    except:
      print('Can not open {} !'.format(filepath))
      return None
    files = {'file': (filename, file)}
    ## 上传文件开始
    try:
      resp = requests.post(apiUrl, files = files)
    except:
      print('Something wrong when uploading file to {}'.format(self._domain))
      return None
    if (resp.status_code != 200):
      print('Upload status_code != 200')
      return None
    try:
      print('Upload respone is:\n{}'.format(resp.text))
      respJson = json.loads(resp.text)
      url = respJson['url']
    except:
      print('Upload respone is not json or have no "url"!')
      return None
    return {'url': url, 'data': resp.text}  
  
class png8_com_Uploader(Uploader):
  '''继承抽象类Uploader的png8_com_Uploader类,
  域名www.png8.com(109.206.246.248)
  '''
  
  def __init__(self):
    Uploader.__init__(self, 'www.png8.com')
    return
    
  def _uploadFile(self, filepath):
    apiUrl = r'https://www.png8.com/api/upload' # 上传文件url
    filename = urllib.parse.quote(os.path.basename(filepath)) # 处理文件名
    ## 制作上传需要的数据资料
    try:
      file = open(filepath,'rb')
    except:
      print('Can not open {} !'.format(filepath))
      return None
    files = {'file': (filename, file)}
    ## 上传文件开始
    try:
      resp = requests.post(apiUrl, files = files)
    except:
      print('Something wrong when uploading file to {}'.format(self._domain))
      return None
    if (resp.status_code != 200):
      print('Upload status_code != 200')
      return None
    try:
      print('Upload respone is:\n{}'.format(resp.text))
      respJson = json.loads(resp.text)
      url = respJson['url']
    except:
      print('Upload respone is not json or have no "url"!')
      return None
    return {'url': url, 'data': resp.text}  
  
class sm_ms_Uploader(Uploader):
  '''继承抽象类Uploader的sm_ms_Uploader类,域名sm.ms(47.88.229.110)'''

  def __init__(self):
    Uploader.__init__(self, 'sm.ms')
    return
    
  def _uploadFile(self, filepath):
    apiUrl = r'https://sm.ms/api/v2/upload' # 上传文件url
    filename = urllib.parse.quote(os.path.basename(filepath)) # 处理文件名
    ## 制作上传需要的数据资料
    try:
      file = open(filepath,'rb')
    except:
      print('Can not open {} !'.format(filepath))
      return None
    files = {'smfile': (filename, file)}
    ## 上传文件开始
    try:
      headers = {}
      #print(headers)
      #headers["Authorization"] = "14ac5499cfdd2bb2859e4476d2e5b1d2bad079bf"
      resp = requests.post(apiUrl, files = files, headers = headers)
    except Exception as e:
      print('Something wrong when uploading file to {}'.format(self._domain))
      #print(e)
      return None
    if (resp.status_code != 200):
      print('Upload status_code != 200')
      return None
    try:
      print('Upload respone is:\n{}'.format(resp.text))
      respJson = json.loads(resp.text)
      url = respJson['data']['url']
    except:
      print('Upload respone is not json or have no ["data"]["url"]!')
      return None
    return {'url': url, 'data': resp.text}

class img_vim_cn_com_Uploader(Uploader):
  '''继承抽象类Uploader的img_vim_cn_com_Uploader类,
  域名img.vim-cn.com(104.28.23.25)
  '''
  
  def __init__(self):
    Uploader.__init__(self, 'img.vim-cn.com')
    return
    
  def _uploadFile(self, filepath):
    apiUrl = r'https://img.vim-cn.com/' # 上传文件url
    filename = urllib.parse.quote(os.path.basename(filepath)) # 处理文件名
    ## 制作上传需要的数据资料
    try:
      file = open(filepath,'rb')
    except:
      print('Can not open {} !'.format(filepath))
      return None
    files = {'image': (filename, file)}
    ## 上传文件开始
    try:
      resp = requests.post(apiUrl, files = files)
    except:
      print('Something wrong when uploading file to {}'.format(self._domain))
      return None
    if (resp.status_code != 200):
      print('Upload status_code != 200')
      return None
    url = resp.text.strip('\n')
    print('Upload respone is:\n{}'.format(url))
    return {'url': url, 'data': url}
    
class niupic_com_Uploader(Uploader):
  '''继承抽象类Uploader的niupic_com_Uploader_Uploader类,
  域名niupic.com(104.31.9.159)
  '''

  def __init__(self):
    Uploader.__init__(self, 'niupic.com')
    return
    
  def _uploadFile(self, filepath):
    apiUrl = r'https://niupic.com/index/upload/process' # 上传文件url
    filename = urllib.parse.quote(os.path.basename(filepath)) # 处理文件名
    ## 制作上传需要的数据资料
    try:
      file = open(filepath,'rb')
    except:
      print('Can not open {} !'.format(filepath))
      return None
    files = {'image_field': (filename, file)}
    headers = {}
    headers['Referer'] = r'https://niupic.com/'
    ## 上传文件开始
    try:
      #resp = requests.post(apiUrl, files = files, headers = headers)
      session = requests.Session()
      resp = session.get(r'https://niupic.com/', headers = headers)
      resp = session.post(apiUrl, files = files)
    except:
      print('Something wrong when uploading file to {}'.format(self._domain))
      return None
    if (resp.status_code != 200):
      print('Upload status_code != 200,status_code = {}'.format(
        resp.status_code))
      return None
    ## 上传完毕分析结果
    try:
      print('Upload respone is:\n{}'.format(resp.text))
      respJson = json.loads(resp.text)
      url = 'https://'+respJson['data']
    except:
      print('Upload respone is not json or have no \
        ["data"]')
      return None
    return {'url': url, 'data': resp.text}   


## 测试
if __name__ == '__main__':

  up = niupic_com_Uploader()

  filepath =  r'D:\MyDocument\MyPic\其他\_until20190512\我与suzuka的Q版结婚证_改2.jpg'

  tags = ['重要']
  _type = '铃鹿'
  
  ## 设定结束,上传前确认
  x = input('input 0+enter to upload')
  if (x == '0'):
    print(up.upload(filepath, tags, _type))